package com.ming_za.odupdaterserver.core.utils;

import com.ming_za.odupdaterserver.core.config.ConfigManager;
import com.ming_za.odupdaterserver.core.config.type.IntValue;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.concurrent.atomic.AtomicLong;

@Component
public class FileUtils {

    public String getFileName(String fileUrl) {
        return fileUrl.substring(fileUrl.lastIndexOf("\\") + 1);
    }

    /**
     * 速率限制-流传输
     * @param outputStream 输出流
     * @param inputStream 输入流
     * @param limit 限制速率，单位：byte
     */
    public void limitStreamTransmit(OutputStream outputStream, InputStream inputStream,int limit,Transmitter transmitter) throws IOException {

        byte[] buffer = new byte[1024];
        long startTime = System.currentTimeMillis();
        long transmitSize = 0;
        int bytesRead;

        try (outputStream; inputStream) {
            while ((bytesRead = inputStream.read(buffer)) > -1) {

                transmitSize += bytesRead;
                transmitter.transmit(outputStream,buffer,bytesRead);

                long elapsedTime = System.currentTimeMillis() - startTime;
                long expectedTime = (transmitSize * 1000) / limit;

                if (elapsedTime < expectedTime) {
                    Thread.sleep(expectedTime - elapsedTime);
                }

            }
        } catch (InterruptedException ignored) {
        }
    }

    /**
     * 无速率限制-流传输
     * @param outputStream 输出流
     * @param inputStream 输入流
     */
    public void streamTransmit(OutputStream outputStream, InputStream inputStream,Transmitter transmitter) throws IOException {
        byte[] buffer = new byte[2048];
        int bytesRead;
        try (outputStream; inputStream) {
            while ((bytesRead = inputStream.read(buffer)) > -1) {
                transmitter.transmit(outputStream,buffer,bytesRead);
            }
        }
    }

    public interface Transmitter {
        void transmit(OutputStream outputStream,byte[] buffer,int dataSize) throws IOException;
    }

    @Component
    public static class NormalTransmitter implements Transmitter {

        @Override
        public void transmit(OutputStream outputStream,byte[] buffer, int dataSize) throws IOException {
            outputStream.write(buffer,0,dataSize);
        }
    }

    @Component
    public static class LimitedTransmitter implements Transmitter {

        private final AtomicLong transmitSize = new AtomicLong(0L);

        public long limit;

        public LimitedTransmitter(ConfigManager configManager) {
            IntValue maxDownloadBroadband = configManager.getMaxDownloadBroadband();
            this.limit = maxDownloadBroadband.getValue() * 131072;

            //更新同步
            maxDownloadBroadband.bindListener((v)->{
                this.limit = v * 131072;
            });
        }

        private void applyTransmit(int bytes){
            if (transmitSize.longValue() >= limit){
                synchronized (transmitSize){
                    if (transmitSize.longValue() >= limit){
                        try {
                            Thread.sleep(1000);
                        } catch (InterruptedException e) {
                            return;
                        }
                        transmitSize.set(0L);
                    }
                }
            }
            transmitSize.addAndGet(bytes);
        }

        @Override
        public void transmit(OutputStream outputStream, byte[] buffer, int dataSize) throws IOException {
            applyTransmit(dataSize);
            outputStream.write(buffer,0,dataSize);
        }
    }

}
